fix(graph): stable USAGE-edge ownership for directory-module nodes#844
Merged
Conversation
Since #667 every file in a Java/Go package shares a directory-based module QN that collides with the pipeline's Folder/Project node. Class-level references resolved their enclosing scope to that shared node, whose file_path was clobbered by each file's always-emitted Module def — last writer wins (sequential upsert) or last-merged worker wins (parallel merge) — so USAGE-edge sources conflated across same-package files and varied run to run. Three coordinated changes: - cbm_gbuf_upsert_node: a Module def colliding with a Project/Folder node no longer updates ANY field (the #667 guard only protected the label). - merge_update_existing: same guard on the parallel worker-gbuf merge path; the ID remap stays outside the guard so worker edges still redirect onto the canonical node. - Source-node finders (pass_usages, pass_parallel, pass_calls) treat a lookup landing on a Folder/Project container as a miss and fall back to the per-file File node (new cbm_pipeline_node_is_dir_container helper). Adds tests/repro/repro_issue787.c: exact-source-set, 5-run stability, and >50-file parallel-path guards (red on the unfixed code in both sequential and parallel flavors). Distilled from #828: the author's commits lacked DCO sign-off trailers and could not be cherry-picked; content applied verbatim plus one clang-format fix in graph_buffer.c. Closes #787. Co-authored-by: Tommy Corbett <spde89@gmail.com> Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
fix(graph): stable USAGE-edge ownership for directory-module nodes
Distilled from #828 (author: Tommy Corbett spde89@gmail.com). The original
commits lacked DCO sign-offs and could not be salvaged by cherry-pick; the
content is applied verbatim plus one clang-format fix (graph_buffer.c — the
moved guard's
strcmpcondition joined to one line). Authorship is creditedvia
Co-authored-by.Closes #787.
Problem
Since #667 switched Java/Go module QNs to directory-based QNs, every file in a
package shares one module QN — which also collides with the pipeline's
Folder/Project node for that directory. Class-level references (e.g.
private IRepository repo;) resolve their enclosing scope to that shareddirectory node, so USAGE edges from all same-package files conflate into a
single source node whose
file_pathis whichever file was processed last(sequential upsert) or whichever worker merged last (parallel merge) —
nondeterministic, varying run to run (#787).
Fix — three verified mechanisms
cbm_gbuf_upsert_node(src/graph_buffer/graph_buffer.c) — the QA: reproduce-first bug suite + LSP/grammar extraction fixes (5-platform board green) #667guard only protected the structural node's label; a per-file Module def
still clobbered its name/file_path/range/properties in place. The guard now
skips the update entirely (early
return existing->id;), protecting allfields of a Project/Folder node from Module-def collisions.
merge_update_existing(src/graph_buffer/graph_buffer.c) — theparallel worker-gbuf merge applied unconditional "src wins", relabelling the
Folder node to Module and setting its file_path to the last-merged worker's
file. The same Module-on-container guard is applied; the ID remap stays
outside the guard so worker edges are still redirected onto the
canonical node.
cbm_pipeline_node_is_dir_container()(src/pipeline/pipeline_internal.h);calls_find_source(pass_calls.c),find_source_node(pass_parallel.c) andfind_enclosing_node(pass_usages.c) treat a lookup that lands on aFolder/Project node as a miss, so every file's class-level usages attribute
to that file's unique File node.
Regression guard
tests/repro/repro_issue787.c(registered in Makefile.cbm + repro_main.c),three tests on a minimal spring-petclinic analog (owner/IRepository.java +
owner/ServiceA.java + owner/ServiceB.java + web/WebController.java):
repro_issue787_usage_exact_sources— single sequential index: USAGEsources of
IRepositorymust be exactly {ServiceA.java, ServiceB.java,WebController.java}.
repro_issue787_usage_stable_across_runs— 5 independent index rounds mustreturn the identical, correct source set.
repro_issue787_usage_stable_parallel— same core fixture padded with 60filler classes (>50 files → parallel worker path), 3 rounds, exact set each
round.
Red/green evidence
RED on unfixed
origin/main(9871e7e) production sources, with the guard testin place (0/3):
(The bogus
owner/IRepository.java/owner/Filler34.javaentries are thelast-writer-clobbered Folder-node file_path — the exact #787 symptom, in both
its sequential and parallel/race flavors.)
GREEN with the fix (3/3):
Additional verification:
make -f Makefile.cbm cbm(-Werror) clean;make -f Makefile.cbm lint-ci(cppcheck + clang-format + NOLINT) green;graph_buffer/pipeline/parallel/incremental/integration suites green
(471 passed).
Note: the repro tests were verified with
CBM_INDEX_SUPERVISOR=0(in-processindexing). Without the kill switch, every
rh_index_files-based repro teston current main hangs: the #827 index supervisor spawns
argv[0] cli --index-worker ..., and the repro runner selects suites via the inheritedCBM_REPRO_ONLYenv (ignoring argv), so the worker child re-runs the reprosuite recursively. That is a pre-existing main-level issue introduced by #827,
independent of this fix — tracked separately.